home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / comms / rzsz0306.arj / RZ.C < prev    next >
C/C++ Source or Header  |  1994-03-02  |  28KB  |  1,303 lines

  1. #define VERSION "3.34 02-18-94"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*
  5.  *
  6.  * rz.c By Chuck Forsberg
  7.  *    Copyright 1994 Omen Technology Inc All Rights Reserved
  8.  *
  9.  * A program for Unix to receive files and commands from computers running
  10.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  11.  *  rz uses Unix buffered input to reduce wasted CPU time.
  12.  *
  13.  *
  14.  *    This version implements numerous enhancements including ZMODEM
  15.  *    Run Length Encoding and variable length headers.  These
  16.  *    features were not funded by the original Telenet development
  17.  *    contract.
  18.  * 
  19.  *  This software may be freely used for educational (didactic
  20.  *  only) purposes.  This software may also be freely used to
  21.  *  support file transfer operations to or from licensed Omen
  22.  *  Technology products.  Use with other commercial or shareware
  23.  *  programs (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION.
  24.  *
  25.  *  Any programs which incorporate part or all of this code must be
  26.  *  provided in source form with this notice intact except by
  27.  *  prior written permission from Omen Technology Incorporated.
  28.  *  This includes compiled executables of this program.
  29.  *
  30.  *   The .doc files and the file "mailer.rz" must also be included.
  31.  * 
  32.  * Use of this software for commercial or administrative purposes
  33.  * except when exclusively limited to interfacing Omen Technology
  34.  * products requires a per port license payment of $20.00 US per
  35.  * port (less in quantity, see mailer.rz).  Use of this code by
  36.  * inclusion, decompilation, reverse engineering or any other means
  37.  * constitutes agreement to these conditions and acceptance of
  38.  * liability to license the materials and payment of reasonable
  39.  * legal costs necessary to enforce this license agreement.
  40.  *
  41.  *
  42.  *        Omen Technology Inc
  43.  *        Post Office Box 4681
  44.  *        Portland OR 97208
  45.  *
  46.  *    This code is made available in the hope it will be useful,
  47.  *    BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
  48.  *    DAMAGES OF ANY KIND.
  49.  *
  50.  *
  51.  *
  52.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  53.  *
  54.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  55.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  56.  *
  57.  *  -DMD may be added to compiler command line to compile in
  58.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  59.  *
  60.  *  HOWMANY may be tuned for best performance
  61.  *
  62.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  63.  */
  64.  
  65. char *Copyrrz = "Copyright 1994 Omen Technology Inc All Rights Reserved";
  66.  
  67.  
  68. #define LOGFILE "/tmp/rzlog"
  69. #define LOGFILE2 "rzlog"
  70. #include <stdio.h>
  71. #include <signal.h>
  72. #include <ctype.h>
  73. #include <errno.h>
  74. extern int errno;
  75.  
  76. #define OK 0
  77. #define FALSE 0
  78. #define TRUE 1
  79. #define ERROR (-1)
  80.  
  81. /*
  82.  * Max value for HOWMANY is 255.
  83.  *   A larger value reduces system overhead but may evoke kernel bugs.
  84.  */
  85. #ifndef HOWMANY
  86. #define HOWMANY 96
  87. #endif
  88.  
  89. /* Ward Christensen / CP/M parameters - Don't change these! */
  90. #define ENQ 005
  91. #define CAN ('X'&037)
  92. #define XOFF ('s'&037)
  93. #define XON ('q'&037)
  94. #define SOH 1
  95. #define STX 2
  96. #define EOT 4
  97. #define ACK 6
  98. #define NAK 025
  99. #define CPMEOF 032
  100. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  101. #define TIMEOUT (-2)
  102. #define RCDO (-3)
  103. #define GCOUNT (-4)
  104. #define ERRORMAX 5
  105. #define RETRYMAX 5
  106. #define WCEOT (-10)
  107. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  108. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  109.  
  110. int Zmodem=0;        /* ZMODEM protocol requested */
  111. int Nozmodem = 0;    /* If invoked as "rb" */
  112. unsigned Baudrate = 9600;
  113. unsigned Effbaud = 9600;
  114.  
  115.  
  116. #include "rbsb.c"    /* most of the system dependent stuff here */
  117. #include "crctab.c"
  118. char endmsg[90] = {0};    /* Possible message to display on exit */
  119.  
  120. char *substr();
  121. FILE *fout;
  122.  
  123. /*
  124.  * Routine to calculate the free bytes on the current file system
  125.  *  ~0 means many free bytes (unknown)
  126.  */
  127. long getfree()
  128. {
  129.     return(2147483647);    /* many free bytes ... */
  130. }
  131.  
  132. int Lastrx;
  133. long rxbytes;
  134. int Crcflg;
  135. int Firstsec;
  136. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  137. int errors;
  138. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  139.  
  140. #define DEFBYTL 2000000000L    /* default rx file size */
  141. long Bytesleft;    /* number of bytes of incoming file left */
  142. long Modtime;        /* Unix style mod time for incoming file */
  143. int Filemode;        /* Unix style mode for incoming file */
  144. long Totalleft;
  145. long Filesleft;
  146. char Pathname[PATHLEN];
  147. char *Progname;        /* the name by which we were called */
  148.  
  149. int Batch=0;
  150. int Thisbinary;        /* current file is to be received in bin mode */
  151. int Rxbinary=FALSE;    /* receive all files in bin mode */
  152. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  153. int Blklen;        /* record length of received packets */
  154.  
  155. #ifdef SEGMENTS
  156. int chinseg = 0;    /* Number of characters received in this data seg */
  157. char secbuf[1+(SEGMENTS+1)*1024];
  158. #else
  159. char secbuf[1025];
  160. #endif
  161.  
  162.  
  163. time_t timep[2];
  164. char Lzmanag;        /* Local file management request */
  165. char Lzconv;        /* Local ZMODEM file conversion request */
  166. char zconv;        /* ZMODEM file conversion request */
  167. char zmanag;        /* ZMODEM file management request */
  168. char ztrans;        /* ZMODEM file transport request */
  169. int Zctlesc;        /* Encode control characters */
  170. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  171.  
  172. /*
  173.  * Log an error
  174.  */
  175. /*VARARGS1*/
  176. void
  177. zperr(s,p,u)
  178. char *s, *p, *u;
  179. {
  180.     if (Verbose <= 0)
  181.         return;
  182.     fprintf(stderr, "Retry %d: ", errors);
  183.     fprintf(stderr, s, p, u);
  184.     fprintf(stderr, "\n");
  185. }
  186.  
  187. #include "zm.c"
  188. #include "zmr.c"
  189.  
  190. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  191.  
  192. /* called by signal interrupt or terminate to clean things up */
  193. void
  194. bibi(n)
  195. {
  196.     if (Zmodem)
  197.         zmputs(Attn);
  198.     canit(); mode(0);
  199.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  200.     exit(3);
  201. }
  202.  
  203. main(argc, argv)
  204. char *argv[];
  205. {
  206.     register char *cp;
  207.     register npats;
  208.     char *virgin, **patts;
  209.     int exitcode = 0;
  210.  
  211.     Rxtimeout = 100;
  212.     setbuf(stderr, NULL);
  213.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  214.         Restricted=TRUE;
  215.  
  216.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  217.     inittty();
  218.     npats = 0;
  219.     while (--argc) {
  220.         cp = *++argv;
  221.         if (*cp == '-') {
  222.             ++cp;
  223.             while( *cp) {
  224.                 if (isdigit(*cp)) {
  225.                     ++cp;  continue;
  226.                 }
  227.                 switch(*cp++) {
  228.                 case '\\':
  229.                      *cp = toupper(*cp);  continue;
  230.                 case 'a':
  231.                     if (!Batch || Nozmodem)
  232.                         Rxascii=TRUE;
  233.                     else
  234.                         usage();
  235.                     break;
  236.                 case 't':
  237.                     if (isdigit(*cp))
  238.                         Rxtimeout = atoi(cp);
  239.                     else {
  240.                         if (--argc < 1)
  241.                             usage();
  242.                         Rxtimeout = atoi(*++argv);
  243.                     }
  244.                     if (Rxtimeout<1 || Rxtimeout>1000)
  245.                         usage();
  246.                     break;
  247.                 case 'w':
  248.                     if (isdigit(*cp))
  249.                         Zrwindow = atoi(cp);
  250.                     else {
  251.                         if (--argc < 1)
  252.                             usage();
  253.                         Zrwindow = atoi(*++argv);
  254.                     }
  255.                     break;
  256.                 case 'v':
  257.                     ++Verbose; break;
  258.                 default:
  259.                     usage();
  260.                 }
  261.             }
  262.         }
  263.         else if ( !npats && argc>0) {
  264.             if (argv[0][0]) {
  265.                 npats=argc;
  266.                 patts=argv;
  267.             }
  268.         }
  269.     }
  270.     if (npats > 1)
  271.         usage();
  272.     if (Batch && npats)
  273.         usage();
  274.     if (Verbose) {
  275.         if (freopen(LOGFILE, "a", stderr)==NULL)
  276.             if (freopen(LOGFILE2, "a", stderr)==NULL) {
  277.                 printf("Can't open log file!");
  278.                 exit(2);
  279.             }
  280.         setbuf(stderr, NULL);
  281.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  282.     }
  283.     vfile("%s %s for %s tty=%s\n", Progname, VERSION, OS, Nametty);
  284.     mode(1);
  285.     if (signal(SIGINT, bibi) == SIG_IGN) {
  286.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  287.     }
  288.     else {
  289.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  290.     }
  291.     signal(SIGTERM, bibi);
  292.     if (wcreceive(npats, patts)==ERROR) {
  293.         exitcode=1;
  294.         canit();
  295.     }
  296.     mode(0);
  297.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  298.         canit();
  299.     if (endmsg[0])
  300.         printf("  %s: %s\r\n", Progname, endmsg);
  301.     printf("%s %s finished.\r\n", Progname, VERSION);
  302.     fflush(stdout);
  303.     if(exitcode)
  304.         exit(1);
  305. #ifndef REGISTERED
  306.     /* Removing or disabling this code without registering is theft */
  307.     if (!Usevhdrs)  {
  308.         printf( "\n\n\nPlease read the License Agreement in rz.doc\n");
  309.         fflush(stdout);
  310.         sleep(10);
  311.     }
  312. #endif
  313.     exit(0);
  314. }
  315.  
  316.  
  317. usage()
  318. {
  319.     fprintf(stderr,
  320.     "Receive Files and Commands with ZMODEM/YMODEM/XMODEM Protocol\n\n");
  321.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  322.       Progname, VERSION, OS);
  323.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n\n");
  324.     fprintf(stderr,"Usage:    rz [-v]        (ZMODEM)\n");
  325.     fprintf(stderr,"or    rb [-av]    (YMODEM)\n");
  326.     fprintf(stderr,"or    rc [-av] file    (XMODEM-CRC)\n");
  327.     fprintf(stderr,"or    rx [-av] file    (XMODEM)\n\n");
  328.     fprintf(stderr,
  329. "Supports the following incoming ZMODEM options given to the sending program:\n\
  330.     compression (-Z), binary (-b), ASCII CR/LF>NL (-a), newer(-n),\n\
  331.     newer+longer(-N), protect (-p), Crash Recovery (-r),\n\
  332.     clobber (-y), match+clobber (-Y),  and append (-+).\n\n");
  333.     fprintf(stderr,"Copyright 1994 Omen Technology INC All Rights Reserved\n");
  334.     fprintf(stderr,
  335.     "See rz.doc for option descriptions and licensing information.\n\n");
  336.     fprintf(stderr,
  337.     "This program is intended to interface with terminal programs,\nnot to act as one.\n\n");
  338.     exit(2);
  339. }
  340.  
  341. /*
  342.  * Let's receive something already.
  343.  */
  344.  
  345. char *rbmsg = "%s ready. Type \"%s file ...\" to your modem program\n\r";
  346.  
  347. wcreceive(argc, argp)
  348. char **argp;
  349. {
  350.     register c;
  351.  
  352.     if (Batch || argc==0) {
  353.         Crcflg=1;
  354.         fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  355.         if (c=tryz()) {
  356.             if (c == ZCOMPL)
  357.                 return OK;
  358.             if (c == ERROR)
  359.                 goto fubar;
  360.             c = rzfiles();
  361.             if (c)
  362.                 goto fubar;
  363.         } else {
  364.             for (;;) {
  365.                 if (wcrxpn(secbuf)== ERROR)
  366.                     goto fubar;
  367.                 if (secbuf[0]==0)
  368.                     return OK;
  369.                 if (procheader(secbuf) == ERROR)
  370.                     goto fubar;
  371.                 if (wcrx()==ERROR)
  372.                     goto fubar;
  373.             }
  374.         }
  375.     } else {
  376.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  377.  
  378.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  379.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  380.         if ((fout=fopen(Pathname, "w")) == NULL)
  381.             return ERROR;
  382.         if (wcrx()==ERROR)
  383.             goto fubar;
  384.     }
  385.     return OK;
  386. fubar:
  387.     canit();
  388.     Modtime = 1;
  389.     if (fout)
  390.         fclose(fout);
  391.     if (Restricted) {
  392.         unlink(Pathname);
  393.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  394.     }
  395.     return ERROR;
  396. }
  397.  
  398.  
  399. /*
  400.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  401.  * Length is indeterminate as long as less than Blklen
  402.  * A null string represents no more files (YMODEM)
  403.  */
  404. wcrxpn(rpn)
  405. char *rpn;    /* receive a pathname */
  406. {
  407.     register c;
  408.  
  409.     purgeline();
  410.  
  411. et_tu:
  412.     Firstsec=TRUE;  Eofseen=FALSE;
  413.     sendline(Crcflg?WANTCRC:NAK);  flushmo();
  414.     Lleft=0;    /* Do read next time ... */
  415.     while ((c = wcgetsec(rpn, 100)) != 0) {
  416.         if (c == WCEOT) {
  417.             zperr( "Pathname fetch returned %d", c);
  418.             sendline(ACK);  flushmo();
  419.             Lleft=0;    /* Do read next time ... */
  420.             readline(1);
  421.             goto et_tu;
  422.         }
  423.         return ERROR;
  424.     }
  425.     sendline(ACK);  flushmo();
  426.     return OK;
  427. }
  428.  
  429. /*
  430.  * Adapted from CMODEM13.C, written by
  431.  * Jack M. Wierda and Roderick W. Hart
  432.  */
  433.  
  434. wcrx()
  435. {
  436.     register int sectnum, sectcurr;
  437.     register char sendchar;
  438.     int cblklen;            /* bytes to dump this block */
  439.  
  440.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  441.     sendchar=Crcflg?WANTCRC:NAK;
  442.  
  443.     for (;;) {
  444.         sendline(sendchar);    /* send it now, we're ready! */
  445.         flushmo();
  446.         Lleft=0;    /* Do read next time ... */
  447.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  448.         if (sectcurr==(sectnum+1 &0377)) {
  449.             sectnum++;
  450.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  451.             if (putsec(secbuf, cblklen)==ERROR)
  452.                 return ERROR;
  453.             if ((Bytesleft-=cblklen) < 0)
  454.                 Bytesleft = 0;
  455.             sendchar=ACK;
  456.         }
  457.         else if (sectcurr==(sectnum&0377)) {
  458.             zperr( "Received dup Sector");
  459.             sendchar=ACK;
  460.         }
  461.         else if (sectcurr==WCEOT) {
  462.             if (closeit())
  463.                 return ERROR;
  464.             sendline(ACK); flushmo();
  465.             Lleft=0;    /* Do read next time ... */
  466.             return OK;
  467.         }
  468.         else if (sectcurr==ERROR)
  469.             return ERROR;
  470.         else {
  471.             zperr( "Sync Error");
  472.             return ERROR;
  473.         }
  474.     }
  475. }
  476.  
  477. /*
  478.  * Wcgetsec fetches a Ward Christensen type sector.
  479.  * Returns sector number encountered or ERROR if valid sector not received,
  480.  * or CAN CAN received
  481.  * or WCEOT if eot sector
  482.  * time is timeout for first char, set to 4 seconds thereafter
  483.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  484.  *    (Caller must do that when he is good and ready to get next sector)
  485.  */
  486.  
  487. wcgetsec(rxbuf, maxtime)
  488. char *rxbuf;
  489. int maxtime;
  490. {
  491.     register checksum, wcj, firstch;
  492.     register unsigned short oldcrc;
  493.     register char *p;
  494.     int sectcurr;
  495.  
  496.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  497.  
  498.         if ((firstch=readline(maxtime))==STX) {
  499.             Blklen=1024; goto get2;
  500.         }
  501.         if (firstch==SOH) {
  502.             Blklen=128;
  503. get2:
  504.             sectcurr=readline(1);
  505.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  506.                 oldcrc=checksum=0;
  507.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  508.                     if ((firstch=readline(1)) < 0)
  509.                         goto bilge;
  510.                     oldcrc=updcrc(firstch, oldcrc);
  511.                     checksum += (*p++ = firstch);
  512.                 }
  513.                 if ((firstch=readline(1)) < 0)
  514.                     goto bilge;
  515.                 if (Crcflg) {
  516.                     oldcrc=updcrc(firstch, oldcrc);
  517.                     if ((firstch=readline(1)) < 0)
  518.                         goto bilge;
  519.                     oldcrc=updcrc(firstch, oldcrc);
  520.                     if (oldcrc & 0xFFFF)
  521.                         zperr( "CRC");
  522.                     else {
  523.                         Firstsec=FALSE;
  524.                         return sectcurr;
  525.                     }
  526.                 }
  527.                 else if (((checksum-firstch)&0377)==0) {
  528.                     Firstsec=FALSE;
  529.                     return sectcurr;
  530.                 }
  531.                 else
  532.                     zperr( "Checksum");
  533.             }
  534.             else
  535.                 zperr("Sector number garbled");
  536.         }
  537.         /* make sure eot really is eot and not just mixmash */
  538.         else if (firstch==EOT && Lleft==0)
  539.             return WCEOT;
  540.         else if (firstch==CAN) {
  541.             if (Lastrx==CAN) {
  542.                 zperr( "Sender CANcelled");
  543.                 return ERROR;
  544.             } else {
  545.                 Lastrx=CAN;
  546.                 continue;
  547.             }
  548.         }
  549.         else if (firstch==TIMEOUT) {
  550.             if (Firstsec)
  551.                 goto humbug;
  552. bilge:
  553.             zperr( "TIMEOUT");
  554.         }
  555.         else
  556.             zperr( "Got 0%o sector header", firstch);
  557.  
  558. humbug:
  559.         Lastrx=0;
  560.         while(readline(1)!=TIMEOUT)
  561.             ;
  562.         if (Firstsec) {
  563.             sendline(Crcflg?WANTCRC:NAK);  flushmo();
  564.             Lleft=0;    /* Do read next time ... */
  565.         } else {
  566.             maxtime=40; sendline(NAK);  flushmo();
  567.             Lleft=0;    /* Do read next time ... */
  568.         }
  569.     }
  570.     /* try to stop the bubble machine. */
  571.     canit();
  572.     return ERROR;
  573. }
  574.  
  575.  
  576. /*
  577.  * Process incoming file information header
  578.  */
  579. procheader(name)
  580. char *name;
  581. {
  582.     register char *openmode, *p;
  583.     static dummy;
  584.     struct stat f;
  585.  
  586.     /* set default parameters and overrides */
  587.     openmode = "w";
  588.     Thisbinary = (!Rxascii) || Rxbinary;
  589.     if (zconv == ZCBIN && Lzconv != ZCRESUM)
  590.         Lzconv = zconv;            /* Remote Binary override */
  591.     if (Lzconv)
  592.         zconv = Lzconv;
  593.     if (Lzmanag)
  594.         zmanag = Lzmanag;
  595.  
  596.     /*
  597.      *  Process ZMODEM remote file management requests
  598.      */
  599.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  600.         Thisbinary = 0;
  601.     if (zconv == ZCBIN)    /* Remote Binary override */
  602.         Thisbinary = TRUE;
  603.     else if (zmanag == ZMAPND)
  604.         openmode = "a";
  605.  
  606.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  607.  
  608.     if (!name || !*name)
  609.         return OK;
  610.  
  611.     p = name + 1 + strlen(name);
  612.     if (*p) {    /* file coming from Unix or DOS system */
  613.         sscanf(p, "%ld%lo%o%lo%d%ld%d%d",
  614.           &Bytesleft, &Modtime, &Filemode,
  615.           &dummy, &Filesleft, &Totalleft, &dummy, &dummy);
  616.         if (Filemode & UNIXFILE)
  617.             ++Thisbinary;
  618.         if (Verbose) {
  619.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  620.               name, Bytesleft, Modtime, Filemode);
  621.             fprintf(stderr,  "YMODEM header: %s\n", p);
  622.         }
  623.     }
  624.  
  625.  
  626.     else {        /* File coming from CP/M system */
  627.         for (p=name; *p; ++p)        /* change / to _ */
  628.             if ( *p == '/')
  629.                 *p = '_';
  630.  
  631.         if ( *--p == '.')        /* zap trailing period */
  632.             *p = 0;
  633.     }
  634.  
  635.     strcpy(Pathname, name);
  636.     checkpath(name);
  637.  
  638.     if (*name && stat(name, &f)!= -1) {
  639.         zmanag &= ZMMASK;
  640.         vfile("Current %s is %ld %lo", name, f.st_size, f.st_mtime);
  641.         if (Thisbinary && zconv==ZCRESUM) {
  642.             rxbytes = f.st_size & ~511;
  643.             if (Bytesleft < rxbytes) {
  644.                 rxbytes = 0;  goto doopen;
  645.             } else
  646.                 openit(name, "r+");
  647.             if ( !fout)
  648.                 return ZFERR;
  649.             if (fseek(fout, rxbytes, 0)) {
  650.                 closeit();
  651.                 return ZFERR;
  652.             }
  653.             vfile("Crash recovery at %ld", rxbytes);
  654.             return 0;
  655.         }
  656.         else if ((zmanag==ZMNEW) ||
  657.           ((zmanag==ZMNEWL) && Bytesleft <= f.st_size) ) {
  658.             if ((f.st_mtime+1) >= Modtime)
  659.                 goto skipfile;
  660.             goto doopen;
  661.         }
  662.         switch (zmanag & ZMMASK) {
  663.         case ZMCLOB:
  664.         case ZMAPND:
  665.             goto doopen;
  666.         default:
  667.             goto skipfile;
  668.         }
  669.     } else if (zmanag & ZMSKNOLOC) {
  670. skipfile:
  671.         vfile("Skipping %s", name);
  672.         return ZSKIP;
  673.     }
  674. doopen:
  675.     openit(name, openmode);
  676. #ifdef MD
  677.     if ( !fout)
  678.         if (make_dirs(name))
  679.             openit(name, openmode);
  680. #endif
  681.     if ( !fout)
  682.         return ZFERR;
  683.     return 0;
  684. }
  685.  
  686. openit(name, openmode)
  687. char *name, *openmode;
  688. {
  689.     fout = fopen(name, openmode);
  690. }
  691.  
  692. #ifdef MD
  693. /*
  694.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  695.  */
  696.  
  697. /*
  698.  * After a file/link/symlink/dir creation has failed, see if
  699.  * it's because some required directory was not present, and if
  700.  * so, create all required dirs.
  701.  */
  702. make_dirs(pathname)
  703. register char *pathname;
  704. {
  705.     register char *p;        /* Points into path */
  706.     int madeone = 0;        /* Did we do anything yet? */
  707.     int save_errno = errno;        /* Remember caller's errno */
  708.  
  709.     if (errno != ENOENT)
  710.         return 0;        /* Not our problem */
  711.  
  712.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  713.         /* Avoid mkdir of empty string, if leading or double '/' */
  714.         if (p == pathname || p[-1] == '/')
  715.             continue;
  716.         /* Avoid mkdir where last part of path is '.' */
  717.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  718.             continue;
  719.         *p = 0;                /* Truncate the path there */
  720.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  721.             vfile("Made directory %s\n", pathname);
  722.             madeone++;        /* Remember if we made one */
  723.             *p = '/';
  724.             continue;
  725.         }
  726.         *p = '/';
  727.         if (errno == EEXIST)        /* Directory already exists */
  728.             continue;
  729.         /*
  730.          * Some other error in the mkdir.  We return to the caller.
  731.          */
  732.         break;
  733.     }
  734.     errno = save_errno;        /* Restore caller's errno */
  735.     return madeone;            /* Tell them to retry if we made one */
  736. }
  737.  
  738. #if (MD != 2)
  739. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  740. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  741. #define TERM_VALUE(status)    ((status) >> 8)
  742. /*
  743.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  744.  */
  745. mkdir(dpath, dmode)
  746. char *dpath;
  747. int dmode;
  748. {
  749.     int cpid, status;
  750.     struct stat statbuf;
  751.  
  752.     if (stat(dpath,&statbuf) == 0) {
  753.         errno = EEXIST;        /* Stat worked, so it already exists */
  754.         return -1;
  755.     }
  756.  
  757.     /* If stat fails for a reason other than non-existence, return error */
  758.     if (errno != ENOENT) return -1; 
  759.  
  760.     switch (cpid = fork()) {
  761.  
  762.     case -1:            /* Error in fork() */
  763.         return(-1);        /* Errno is set already */
  764.  
  765.     case 0:                /* Child process */
  766.         /*
  767.          * Cheap hack to set mode of new directory.  Since this
  768.          * child process is going away anyway, we zap its umask.
  769.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  770.          * directory.  Does anybody care?
  771.          */
  772.         status = umask(0);    /* Get current umask */
  773.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  774.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  775.         _exit(2);        /* Can't exec /bin/mkdir */
  776.     
  777.     default:            /* Parent process */
  778.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  779.     }
  780.  
  781.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  782.         errno = EIO;        /* We don't know why, but */
  783.         return -1;        /* /bin/mkdir failed */
  784.     }
  785.  
  786.     return 0;
  787. }
  788. #endif /* MD != 2 */
  789. #endif /* MD */
  790.  
  791. /*
  792.  * Putsec writes the n characters of buf to receive file fout.
  793.  *  If not in binary mode, carriage returns, and all characters
  794.  *  starting with CPMEOF are discarded.
  795.  */
  796. putsec(buf, n)
  797. char *buf;
  798. register n;
  799. {
  800.     register char *p;
  801.  
  802.     if (n == 0)
  803.         return OK;
  804.     if (Thisbinary) {
  805.         for (p=buf; --n>=0; )
  806.             putc( *p++, fout);
  807.     }
  808.     else {
  809.         if (Eofseen)
  810.             return OK;
  811.         for (p=buf; --n>=0; ++p ) {
  812.             if ( *p == '\r')
  813.                 continue;
  814.             if (*p == CPMEOF) {
  815.                 Eofseen=TRUE; return OK;
  816.             }
  817.             putc(*p ,fout);
  818.         }
  819.     }
  820.     return OK;
  821. }
  822.  
  823. /*
  824.  * substr(string, token) searches for token in string s
  825.  * returns pointer to token within string if found, NULL otherwise
  826.  */
  827. char *
  828. substr(s, t)
  829. register char *s,*t;
  830. {
  831.     register char *ss,*tt;
  832.     /* search for first char of token */
  833.     for (ss=s; *s; s++)
  834.         if (*s == *t)
  835.             /* compare token with substring */
  836.             for (ss=s,tt=t; ;) {
  837.                 if (*tt == 0)
  838.                     return s;
  839.                 if (*ss++ != *tt++)
  840.                     break;
  841.             }
  842.     return NULL;
  843. }
  844.  
  845.  
  846. /*
  847.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  848.  * If called as rb use YMODEM protocol
  849.  */
  850. chkinvok(s)
  851. char *s;
  852. {
  853.     register char *p;
  854.  
  855.     p = s;
  856.     while (*p == '-')
  857.         s = ++p;
  858.     while (*p)
  859.         if (*p++ == '/')
  860.             s = p;
  861.     if (*s == 'v') {
  862.         Verbose=1; ++s;
  863.     }
  864.     Progname = s;
  865.     if (s[0]=='r' && s[1]=='z')
  866.         Batch = TRUE;
  867.     if (s[0]=='r' && s[1]=='c')
  868.         Crcflg = TRUE;
  869.     if (s[0]=='r' && s[1]=='b')
  870.         Batch = Nozmodem = TRUE;
  871. }
  872.  
  873. /*
  874.  * Totalitarian Communist pathname processing
  875.  */
  876. checkpath(name)
  877. char *name;
  878. {
  879.     if (Restricted) {
  880.         if (fopen(name, "r") != NULL) {
  881.             canit();
  882.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  883.             bibi(-1);
  884.         }
  885.         /* restrict pathnames to current tree or uucppublic */
  886.         if ( substr(name, "../")
  887.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  888.             canit();
  889.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  890.             bibi(-1);
  891.         }
  892.     }
  893. }
  894. /*
  895.  * Ack a ZFIN packet, let byegones be byegones
  896.  */
  897. void
  898. ackbibi()
  899. {
  900.     register n;
  901.  
  902.     vfile("ackbibi:");
  903.     Readnum = 1;
  904.     stohdr(0L);
  905.     for (n=3; --n>=0; ) {
  906.         purgeline();
  907.         zshhdr(4,ZFIN, Txhdr);
  908.         switch (readline(100)) {
  909.         case 'O':
  910.             readline(1);    /* Discard 2nd 'O' */
  911.             vfile("ackbibi complete");
  912.             return;
  913.         case RCDO:
  914.             return;
  915.         case TIMEOUT:
  916.         default:
  917.             break;
  918.         }
  919.     }
  920. }
  921.  
  922.  
  923. /*
  924.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  925.  *  Handles ZSINIT frame
  926.  *  Return ZFILE if Zmodem filename received, -1 on error,
  927.  *   ZCOMPL if transaction finished,  else 0
  928.  */
  929. tryz()
  930. {
  931.     register c, n;
  932.     register cmdzack1flg;
  933.  
  934.     if (Nozmodem)        /* Check for "rb" program name */
  935.         return 0;
  936.  
  937.  
  938.     for (n=15; --n>=0; ) {
  939.         /* Set buffer length (0) and capability flags */
  940. #ifdef SEGMENTS
  941.         stohdr(SEGMENTS*1024L);
  942. #else
  943.         stohdr(0L);
  944. #endif
  945. #ifdef CANBREAK
  946.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  947. #else
  948.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  949. #endif
  950.         if (Zctlesc)
  951.             Txhdr[ZF0] |= TESCCTL;
  952.         Txhdr[ZF0] |= CANRLE;
  953.         Txhdr[ZF1] = CANVHDR;
  954.         /* tryzhdrtype may == ZRINIT */
  955.         zshhdr(4,tryzhdrtype, Txhdr);
  956.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  957.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  958. again:
  959.         switch (zgethdr(Rxhdr)) {
  960.         case ZRQINIT:
  961.             if (Rxhdr[ZF3] & 0x80)
  962.                 Usevhdrs = 1;    /* we can var header */
  963.             continue;
  964.         case ZEOF:
  965.             continue;
  966.         case TIMEOUT:
  967.             continue;
  968.         case ZFILE:
  969.             zconv = Rxhdr[ZF0];
  970.             zmanag = Rxhdr[ZF1];
  971.             ztrans = Rxhdr[ZF2];
  972.             if (Rxhdr[ZF3] & ZCANVHDR)
  973.                 Usevhdrs = TRUE;
  974.             tryzhdrtype = ZRINIT;
  975.             c = zrdata(secbuf, 1024);
  976.             if (c == GOTCRCW)
  977.                 return ZFILE;
  978.             zshhdr(4,ZNAK, Txhdr);
  979.             goto again;
  980.         case ZSINIT:
  981.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  982.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  983.                 stohdr(1L);
  984.                 zshhdr(4,ZACK, Txhdr);
  985.                 goto again;
  986.             }
  987.             zshhdr(4,ZNAK, Txhdr);
  988.             goto again;
  989.         case ZFREECNT:
  990.             stohdr(getfree());
  991.             zshhdr(4,ZACK, Txhdr);
  992.             goto again;
  993.         case ZCOMMAND:
  994.             cmdzack1flg = Rxhdr[ZF0];
  995.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  996.                 if (cmdzack1flg & ZCACK1)
  997.                     stohdr(0L);
  998.                 else
  999.                     stohdr((long)sys2(secbuf));
  1000.                 purgeline();    /* dump impatient questions */
  1001.                 do {
  1002.                     zshhdr(4,ZCOMPL, Txhdr);
  1003.                 }
  1004.                 while (++errors<20 && zgethdr(Rxhdr) != ZFIN);
  1005.                 ackbibi();
  1006.                 if (cmdzack1flg & ZCACK1)
  1007.                     exec2(secbuf);
  1008.                 return ZCOMPL;
  1009.             }
  1010.             zshhdr(4,ZNAK, Txhdr); goto again;
  1011.         case ZCOMPL:
  1012.             goto again;
  1013.         default:
  1014.             continue;
  1015.         case ZFIN:
  1016.             ackbibi(); return ZCOMPL;
  1017.         case ZCAN:
  1018.             return ERROR;
  1019.         }
  1020.     }
  1021.     return 0;
  1022. }
  1023.  
  1024. /*
  1025.  * Receive 1 or more files with ZMODEM protocol
  1026.  */
  1027. rzfiles()
  1028. {
  1029.     register c;
  1030.  
  1031.     for (;;) {
  1032.         switch (c = rzfile()) {
  1033.         case ZEOF:
  1034.         case ZSKIP:
  1035.             switch (tryz()) {
  1036.             case ZCOMPL:
  1037.                 return OK;
  1038.             default:
  1039.                 return ERROR;
  1040.             case ZFILE:
  1041.                 break;
  1042.             }
  1043.             continue;
  1044.         default:
  1045.             return c;
  1046.         case ERROR:
  1047.             return ERROR;
  1048.         }
  1049.     }
  1050. }
  1051.  
  1052. /*
  1053.  * Receive a file with ZMODEM protocol
  1054.  *  Assumes file name frame is in secbuf
  1055.  */
  1056. rzfile()
  1057. {
  1058.     register c, n;
  1059.  
  1060.     Eofseen=FALSE;
  1061.     n = 20; rxbytes = 0l;
  1062.  
  1063.     if (c = procheader(secbuf)) {
  1064.         return (tryzhdrtype = c);
  1065.     }
  1066.  
  1067.     for (;;) {
  1068. #ifdef SEGMENTS
  1069.         chinseg = 0;
  1070. #endif
  1071.         stohdr(rxbytes);
  1072.         zshhdr(4,ZRPOS, Txhdr);
  1073. nxthdr:
  1074.         switch (c = zgethdr(Rxhdr)) {
  1075.         default:
  1076.             vfile("rzfile: Wrong header %d", c);
  1077.             if ( --n < 0) {
  1078.                 sprintf(endmsg, "rzfile: Wrong header %d", c);
  1079.                 return ERROR;
  1080.             }
  1081.             continue;
  1082.         case ZCAN:
  1083.             sprintf(endmsg, "Sender CANcelled");
  1084.             return ERROR;
  1085.         case ZNAK:
  1086. #ifdef SEGMENTS
  1087.             putsec(secbuf, chinseg);
  1088.             chinseg = 0;
  1089. #endif
  1090.             if ( --n < 0) {
  1091.                 sprintf(endmsg, "rzfile: got ZNAK", c);
  1092.                 return ERROR;
  1093.             }
  1094.             continue;
  1095.         case TIMEOUT:
  1096. #ifdef SEGMENTS
  1097.             putsec(secbuf, chinseg);
  1098.             chinseg = 0;
  1099. #endif
  1100.             if ( --n < 0) {
  1101.                 sprintf(endmsg, "rzfile: TIMEOUT", c);
  1102.                 return ERROR;
  1103.             }
  1104.             continue;
  1105.         case ZFILE:
  1106.             zrdata(secbuf, 1024);
  1107.             continue;
  1108.         case ZEOF:
  1109. #ifdef SEGMENTS
  1110.             putsec(secbuf, chinseg);
  1111.             chinseg = 0;
  1112. #endif
  1113.             if (rclhdr(Rxhdr) != rxbytes) {
  1114.                 /*
  1115.                  * Ignore eof if it's at wrong place - force
  1116.                  *  a timeout because the eof might have gone
  1117.                  *  out before we sent our zrpos.
  1118.                  */
  1119.                 errors = 0;  goto nxthdr;
  1120.             }
  1121.             if (closeit()) {
  1122.                 tryzhdrtype = ZFERR;
  1123.                 vfile("rzfile: closeit returned <> 0");
  1124.                 sprintf(endmsg,"Error closing file");
  1125.                 return ERROR;
  1126.             }
  1127.             vfile("rzfile: normal EOF");
  1128.             return c;
  1129.         case ERROR:    /* Too much garbage in header search error */
  1130. #ifdef SEGMENTS
  1131.             putsec(secbuf, chinseg);
  1132.             chinseg = 0;
  1133. #endif
  1134.             if ( --n < 0) {
  1135.                 sprintf(endmsg, "Persistent CRC or other ERROR");
  1136.                 return ERROR;
  1137.             }
  1138.             zmputs(Attn);
  1139.             continue;
  1140.         case ZSKIP:
  1141. #ifdef SEGMENTS
  1142.             putsec(secbuf, chinseg);
  1143.             chinseg = 0;
  1144. #endif
  1145.             Modtime = 1;
  1146.             closeit();
  1147.             sprintf(endmsg, "Sender SKIPPED file");
  1148.             return c;
  1149.         case ZDATA:
  1150.             if (rclhdr(Rxhdr) != rxbytes) {
  1151.                 if ( --n < 0) {
  1152.                     sprintf(endmsg,"Data has bad addr");
  1153.                     return ERROR;
  1154.                 }
  1155. #ifdef SEGMENTS
  1156.                 putsec(secbuf, chinseg);
  1157.                 chinseg = 0;
  1158. #endif
  1159.                 zmputs(Attn);  continue;
  1160.             }
  1161. moredata:
  1162.             if (Verbose>1)
  1163.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1164.                   rxbytes, Crc32r?" CRC-32":"");
  1165. #ifdef SEGMENTS
  1166.             if (chinseg >= (1024 * SEGMENTS)) {
  1167.                 putsec(secbuf, chinseg);
  1168.                 chinseg = 0;
  1169.             }
  1170.             switch (c = zrdata(secbuf+chinseg, 1024))
  1171. #else
  1172.             switch (c = zrdata(secbuf, 1024))
  1173. #endif
  1174.             {
  1175.             case ZCAN:
  1176. #ifdef SEGMENTS
  1177.                 putsec(secbuf, chinseg);
  1178.                 chinseg = 0;
  1179. #endif
  1180.                 sprintf(endmsg, "Sender CANcelled");
  1181.                 return ERROR;
  1182.             case ERROR:    /* CRC error */
  1183. #ifdef SEGMENTS
  1184.                 putsec(secbuf, chinseg);
  1185.                 chinseg = 0;
  1186. #endif
  1187.                 if ( --n < 0) {
  1188.                     sprintf(endmsg, "Persistent CRC or other ERROR");
  1189.                     return ERROR;
  1190.                 }
  1191.                 zmputs(Attn);
  1192.                 continue;
  1193.             case TIMEOUT:
  1194. #ifdef SEGMENTS
  1195.                 putsec(secbuf, chinseg);
  1196.                 chinseg = 0;
  1197. #endif
  1198.                 if ( --n < 0) {
  1199.                     sprintf(endmsg, "TIMEOUT");
  1200.                     return ERROR;
  1201.                 }
  1202.                 continue;
  1203.             case GOTCRCW:
  1204.                 n = 20;
  1205. #ifdef SEGMENTS
  1206.                 chinseg += Rxcount;
  1207.                 putsec(secbuf, chinseg);
  1208.                 chinseg = 0;
  1209. #else
  1210.                 putsec(secbuf, Rxcount);
  1211. #endif
  1212.                 rxbytes += Rxcount;
  1213.                 stohdr(rxbytes);
  1214.                 sendline(XON);
  1215.                 zshhdr(4,ZACK, Txhdr);
  1216.                 goto nxthdr;
  1217.             case GOTCRCQ:
  1218.                 n = 20;
  1219. #ifdef SEGMENTS
  1220.                 chinseg += Rxcount;
  1221. #else
  1222.                 putsec(secbuf, Rxcount);
  1223. #endif
  1224.                 rxbytes += Rxcount;
  1225.                 stohdr(rxbytes);
  1226.                 zshhdr(4,ZACK, Txhdr);
  1227.                 goto moredata;
  1228.             case GOTCRCG:
  1229.                 n = 20;
  1230. #ifdef SEGMENTS
  1231.                 chinseg += Rxcount;
  1232. #else
  1233.                 putsec(secbuf, Rxcount);
  1234. #endif
  1235.                 rxbytes += Rxcount;
  1236.                 goto moredata;
  1237.             case GOTCRCE:
  1238.                 n = 20;
  1239. #ifdef SEGMENTS
  1240.                 chinseg += Rxcount;
  1241. #else
  1242.                 putsec(secbuf, Rxcount);
  1243. #endif
  1244.                 rxbytes += Rxcount;
  1245.                 goto nxthdr;
  1246.             }
  1247.         }
  1248.     }
  1249. }
  1250.  
  1251.  
  1252. /*
  1253.  * Close the receive dataset, return OK or ERROR
  1254.  */
  1255. closeit()
  1256. {
  1257.     time_t time();
  1258.  
  1259.     if (fclose(fout)==ERROR) {
  1260.         fprintf(stderr, "file close ERROR\n");
  1261.         return ERROR;
  1262.     }
  1263.     if (Modtime) {
  1264.         timep[0] = time(NULL);
  1265.         timep[1] = Modtime;
  1266.         utime(Pathname, timep);
  1267.     }
  1268.     if (
  1269. #ifdef POSIX
  1270.     S_ISREG(Filemode)
  1271. #else
  1272.     (Filemode&S_IFMT) == S_IFREG
  1273. #endif
  1274.     )
  1275.         chmod(Pathname, (unsigned short)(07777 & Filemode));
  1276.     return OK;
  1277. }
  1278.  
  1279.  
  1280. /*
  1281.  * Strip leading ! if present, do shell escape. 
  1282.  */
  1283. sys2(s)
  1284. register char *s;
  1285. {
  1286.     if (*s == '!')
  1287.         ++s;
  1288.     return system(s);
  1289. }
  1290. /*
  1291.  * Strip leading ! if present, do exec.
  1292.  */
  1293. exec2(s)
  1294. register char *s;
  1295. {
  1296.     if (*s == '!')
  1297.         ++s;
  1298.     mode(0);
  1299.     execl("/bin/sh", "sh", "-c", s);
  1300. }
  1301.  
  1302. /* End of rz.c */
  1303.